package itsm.isperp.workflow.service;

import itsm.isperp.framework.core.context.ContextHolder;
import itsm.isperp.framework.data.dialect.DialectFactory;
import itsm.isperp.framework.data.domain.DataRequest;
import itsm.isperp.framework.data.domain.DataResponse;
import itsm.isperp.framework.data.mybatis.plugin.JqGridResponseData;
import itsm.isperp.framework.domain.IBean;
import itsm.isperp.framework.domain.IUser;
import itsm.isperp.framework.utils.HibernateUUIDGenerator;
import itsm.isperp.framework.utils.Pair;
import itsm.isperp.framework.web.request.JqGridRequest;
import itsm.isperp.module.entity.bpm.BpmActionHistory;
import itsm.isperp.module.entity.bpm.BpmNodeUser;
import itsm.isperp.module.entity.db.DbEntity;
import itsm.isperp.module.service.app.UserAccountService;
import itsm.isperp.module.service.bpm.BpmActionHistoryService;
import itsm.isperp.module.service.bpm.BpmNodeSettingService;
import itsm.isperp.module.service.bpm.BpmNodeUserService;
import itsm.isperp.module.service.bpm.BpmProcessSettingService;
import itsm.isperp.module.service.bpm.act.ActHiProcinstService;
import itsm.isperp.module.service.db.DbEntityService;
import itsm.isperp.module.utils.CandidaterUtils;
import itsm.isperp.workflow.cmd.FindNearestUserTaskCmd;
import itsm.isperp.workflow.cmd.JumpCmd;
import itsm.isperp.workflow.cmd.ReOpenProcessCmd;
import itsm.isperp.workflow.cmd.RollbackTaskCmd;
import itsm.isperp.workflow.cmd.WithdrawTaskCmd;
import itsm.isperp.workflow.dto.BpmTransitionLine;
import itsm.isperp.workflow.engine.diagram.CustomerProcessDiagramGenerator;
import itsm.isperp.workflow.graph.Node;
import itsm.isperp.workflow.graph.ShapeMeta;
import itsm.isperp.workflow.utils.BpmConst;
import itsm.isperp.workflow.utils.BpmScriptUtils;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import javax.imageio.ImageIO;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.EndEvent;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.GraphicInfo;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

/**
 * 
 * 流程运行时服务
 * 
 * @author lizx
 * @date 2013-8-20
 * 
 */
@Service
public class BpmProcessRunService {

  private static Logger logger = LoggerFactory
      .getLogger(BpmProcessDefinitaionService.class);

  Lock lock = new ReentrantLock();

  Lock lockEnd = new ReentrantLock();

  @Autowired
  protected TaskService taskService;

  @Autowired
  protected RuntimeService runtimeService;

  @Autowired
  private RepositoryService repositoryService;

  @Autowired
  BpmProcessDefinitaionService bpmProcessDefinitaionService;

  @Autowired
  BpmProcessSettingService bpmProcessSettingService;

  @Autowired
  BpmNodeSettingService bpmNodeSettingService;

  @Autowired
  DbEntityService dbEntityService;

  @Autowired
  HistoryService historyService;

  @Autowired
  IdentityService identityService;

  @Autowired
  ProcessEngine processEngine;

  @Autowired
  JdbcTemplate jdbcTemplate;

  @Autowired
  BpmActionHistoryService bpmActionHistoryService;

  /**
   * 获取历史数据
   * 
   * @param processInstanceId
   * @return
   */
  public List<Map<String, Object>> getHistory(String processId) {

    return bpmActionHistoryService.findDetailByProcessId(processId);

  }

  public void reOpenProcess(String processInstanceId) {

    processEngine.getManagementService().executeCommand(
        new ReOpenProcessCmd(processInstanceId));

  }

  /**
   * 获取流程追踪的图片
   * 
   * @param processInstanceId
   * @return
   * @throws IOException
   */
  public byte[] traceImage(String processInstanceId) throws IOException {

    String processDefinitionId = null;
    ProcessInstance pi = runtimeService.createProcessInstanceQuery()
        .processInstanceId(processInstanceId).singleResult();
    String curentActivity = null;
    if (pi == null) {
      // 查询已经结束的流程
      HistoricProcessInstance pic = historyService
          .createHistoricProcessInstanceQuery()
          .processInstanceId(processInstanceId).singleResult();

      processDefinitionId = pic.getProcessDefinitionId();

    } else {
      processDefinitionId = pi.getProcessDefinitionId();
      curentActivity = pi.getActivityId();
    }

    List<HistoricActivityInstance> list = historyService
        .createHistoricActivityInstanceQuery()
        .processInstanceId(processInstanceId).list();

    BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

    List<String> listStr = new ArrayList<>();
    List<String> listLine = new ArrayList<>();

    Map<String, HistoricActivityInstance> map = new HashMap<>();

    for (HistoricActivityInstance act : list) {
      String actId = act.getActivityId();
      map.put(actId, act);
      listStr.add(actId);
    }
    List<BpmActionHistory> actions = bpmActionHistoryService
        .findByProcessId(processInstanceId);

    for (BpmActionHistory ah : actions) {

      listLine.add(ah.getActionFlowId());
    }
    Map<String, GraphicInfo> labels = bpmnModel.getLabelLocationMap();
    for (String l : labels.keySet()) {
      GraphicInfo g = labels.get(l);
      FlowElement e = g.getElement();
      if (e instanceof SequenceFlow) {
        SequenceFlow sf = (SequenceFlow) e;
        if (map.containsKey(sf.getSourceRef())
            && map.containsKey(sf.getTargetRef())) {
          if (!"userTask".equals(map.get(sf.getSourceRef()).getActivityType())) {
            listLine.add(l);
          }

        }

      }

    }

    InputStream resourceAsStream = new CustomerProcessDiagramGenerator()
        .generateDiagram(bpmnModel, listStr, listLine, curentActivity);

    BufferedImage buffImg = ImageIO.read(resourceAsStream);

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ImageIO.write(buffImg, "png", out);
    out.close();
    resourceAsStream.close();

    byte[] b = out.toByteArray();
    resourceAsStream.close();
    return b;

  }

  /**
   * 流程跟踪图形化数据图形
   * 
   * @param processInstanceId
   *          实体id
   * @param historys
   *          历史信息
   * @return 数据图形
   * @throws IOException
   * @throws DocumentException
   */
  public ShapeMeta traceShapeMeta(String processInstanceId) throws IOException,
      DocumentException {
    String processDefinitionId = historyService
        .createHistoricProcessInstanceQuery()
        .processInstanceId(processInstanceId).singleResult()
        .getProcessDefinitionId();

    return bpmProcessDefinitaionService
        .getProcessDefinitionShapeMeta(processDefinitionId);

  }

  /**
   * 进入流程（不指定处理人，默认会使用后台登陆者的帐号F）
   * 
   * @param id
   * @param key
   * @return
   */
  public String entry(String id) {
    return entry(id, null, null);
  }

  public String view(String id, String key) {
    return getFormUrl(id, key, true).get("form_url").toString();
  }

  /**
   * 进入下一步的表单
   * 
   * @param id
   *          业务表id
   * @param key
   *          流程的key
   * @return 表达的地址
   */
  public String entry(String id, String key, String fromUser) {

    String username = "";
    String resultUrl = "";
    if (StringUtils.isNotEmpty(fromUser)) {
      username = fromUser;
    } else {
      username = ContextHolder.getLoginUsername();
    }

    Map<String, Object> map = null;
    if (StringUtils.isEmpty(id)) {
      map = getFormUrl(id, key, false);
      if (map.get("form_url").toString().indexOf("?") > 0)
        resultUrl = map.get("form_url").toString() + "&processKey=" + key;
      else
        resultUrl = map.get("form_url").toString() + "?processKey=" + key;

    } else {
      List<Task> list = taskService.createTaskQuery()
          .processInstanceBusinessKey(id).taskCandidateOrAssigned(username)
          .active().list();
      if (list.size() > 0) {
        String sql = "SELECT  form_url  FROM bpm_node_setting ns WHERE act_node_id='"
            + list.get(0).getTaskDefinitionKey() + "'";
        // 用户表单
        map = jdbcTemplate.queryForMap(sql);
        resultUrl = map.get("form_url").toString();

      } else {

        map = getFormUrl(id, key, false);
        resultUrl = map.get("form_url").toString();
      }

    }
    return resultUrl;

  }

  private Map<String, Object> getFormUrl(String id, String key, boolean readonly) {
    String formUrl = null;

    if (StringUtils.isEmpty(id)) {
      formUrl = "form_start_url";
    } else {

      if (readonly) {
        formUrl = "view_url";
      } else {
        // 是否已经启动流程
        HistoricProcessInstance pi = historyService
            .createHistoricProcessInstanceQuery()
            .processInstanceBusinessKey(id).singleResult();

        if (pi == null) {
          formUrl = "form_start_url";
        } else {

          formUrl = "view_url";
          if (StringUtils.isEmpty(key))
            key = pi.getProcessDefinitionId().split(":")[0];
        }
      }

    }

    String sql = "SELECT " + formUrl
        + " AS form_url FROM bpm_process_setting WHERE act_re_procdef_key='"
        + key + "'  " + DialectFactory.getDialect().getLimitString(0, 1);

    return jdbcTemplate.queryForMap(sql);
  }

  public String entryProcess(IBean idBean, String processInstanceId,
      String key, String fromUser) {
    String businessKey = this.historyService
        .createHistoricProcessInstanceQuery()
        .processInstanceId(processInstanceId).singleResult().getBusinessKey();

    idBean.setId(businessKey);

    return this.entry(businessKey, key, fromUser);

  }

  /**
   * 获取下一步流程
   * 
   * @param key
   *          流程key
   * @param processInstanceId
   *          流程实例id
   * @return 流程处理连接线实体列表
   */
  public List<BpmTransitionLine> getNextSteps(String username,
      String businessKey) {
    ProcessInstance pi = runtimeService.createProcessInstanceQuery()
        .processInstanceBusinessKey(businessKey).singleResult();

    return getNextSteps(pi.getProcessDefinitionId(), pi
        .getProcessDefinitionId().split(":")[0], pi.getId(), username);

  }

  public List<BpmTransitionLine> getNextSteps(String processKey,
      String processId, String username) {
    return getNextSteps(null, processKey, processId, username);
  }

  public List<BpmTransitionLine> getNextSteps(String processDefinitionId,
      String processKey, String processId, String username) {
    return getNextStepsAndNodeSetting(processDefinitionId, processKey,
        processId, username).getLeftObject();
  }

  public Pair<List<BpmTransitionLine>, Map<String, Object>> getNextStepsAndNodeSetting(
      String processKey, String processId, String username) {
    return getNextStepsAndNodeSetting(null, processKey, processId, username);
  }

  /**
   * 获取下一步流程
   * 
   * @param key
   *          流程key
   * @param ActivityId
   *          流程节点id
   * @return 流程处理连接线实体列表
   */
  public List<BpmTransitionLine> getNextStepsTransitionLine(String processKey,
      String ActivityId) {

    ProcessDefinitionEntity def = this.bpmProcessDefinitaionService
        .getProcessDefinitionEntityByKey(processKey);

    List<BpmTransitionLine> lines = new ArrayList<BpmTransitionLine>();
    List<PvmTransition> ins = def.findActivity(ActivityId)
        .getOutgoingTransitions();
    // 转换为连接线
    for (PvmTransition tran : ins) {
      if (tran == null) {
        break;
      }
      Object name = tran.getProperty("name");
      if (name == null) {
        continue;
      }
      // pvm的目标环节
      PvmActivity dest = getNextActivity(tran);
      BpmTransitionLine m = new BpmTransitionLine();
      m.setName(name.toString());
      m.setNextTransitionId(tran.getId());
      m.setNextTaskId(dest.getId());

      Map<String, Object> setting = bpmNodeSettingService.findMapByNodeId(
          m.getNextTaskId(), "commit_type", "are_open_comment_window",
          "are_auto_entry_next");
      m.setProcessInstanceId(null);
      if (setting != null) {
        // null next will by a gateway
        Object commit_type = setting.get("commit_type");

        Boolean are_open_comment_window = false, are_auto_entry_next = false;

        if (setting.get("are_open_comment_window") instanceof Boolean) {
          are_open_comment_window = (Boolean) setting
              .get("are_open_comment_window");
        } else {
          are_open_comment_window = setting.get("are_open_comment_window") == null ? false
              : (Integer.valueOf(setting.get("are_open_comment_window")
                  .toString()) == 1 ? true : false);
        }
        if (setting.get("are_auto_entry_next") instanceof Boolean) {
          are_auto_entry_next = (Boolean) setting.get("are_auto_entry_next");
        } else {
          are_auto_entry_next = setting.get("are_auto_entry_next") == null ? false
              : (Integer.valueOf(setting.get("are_auto_entry_next").toString()) == 1 ? true
                  : false);
        }

        m.setCommitType(commit_type == null ? 0 : Integer.parseInt(commit_type
            .toString()));
        m.setAreAutoEntryNext(are_open_comment_window);
        m.setAreAutoEntryNext(are_auto_entry_next);

      }
      lines.add(m);
    }

    return lines;

  }

  /**
   * 获取当前节点nodeId
   * 
   * @param key
   *          流程key
   * @param processInstanceId
   *          流程实例id
   * @return 当前节点nodeId
   */
  public String getActId(String processDefinitionId, String processKey,
      String processId) {
    ProcessDefinitionEntity def = null;
    String result = "";
    if (processDefinitionId == null) {
      if (StringUtils.isEmpty(processId)) {

        def = this.bpmProcessDefinitaionService
            .getProcessDefinitionEntityByKey(processKey);
      } else {

        def = this.bpmProcessDefinitaionService
            .getProcessDefinitionEntityByProcessInstanceId(processId);
      }
    } else {
      def = this.bpmProcessDefinitaionService
          .getProcessDefinitionEntityByProcessDefinitionId(processDefinitionId);
    }
    if (StringUtils.isEmpty(processId)) {
      // 如果流程未启动,取得流程定义的其实节点
      ActivityImpl actImpl = def.getInitial();
      result = actImpl.getId();
    } else {
      TaskQuery tq = taskService.createTaskQuery().processInstanceId(processId)
          .processDefinitionKey(processKey);
      Task tk = tq.singleResult();
      if (tk != null)
        result = tk.getTaskDefinitionKey();
      else
        result = null;

    }
    return result;

  }

  /**
   * 获取下一步流程
   * 
   * @param key
   *          流程key
   * @param processInstanceId
   *          流程实例id
   * @return 流程处理连接线实体列表
   */
  public Pair<List<BpmTransitionLine>, Map<String, Object>> getNextStepsAndNodeSetting(
      String processDefinitionId, String processKey, String processId,
      String username) {
    Pair<List<BpmTransitionLine>, Map<String, Object>> pair = new Pair<List<BpmTransitionLine>, Map<String, Object>>();
    if (StringUtils.isEmpty(processKey)) {
      return null;
    }
    ProcessDefinitionEntity def = null;
    if (processDefinitionId == null) {
      if (StringUtils.isEmpty(processId)) {

        def = this.bpmProcessDefinitaionService
            .getProcessDefinitionEntityByKey(processKey);
      } else {

        def = this.bpmProcessDefinitaionService
            .getProcessDefinitionEntityByProcessInstanceId(processId);
      }
    } else {
      def = this.bpmProcessDefinitaionService
          .getProcessDefinitionEntityByProcessDefinitionId(processDefinitionId);
    }

    List<PvmTransition> ins = null;
    ActivityImpl thisActivity = null;
    // 流程未启动
    if (StringUtils.isEmpty(processId)) {
      // 如果流程未启动,取得流程定义的其实节点
      ins = def.getInitial().getOutgoingTransitions();
    } else {
      // 流程已结束,返回
      if (isProcessFinished(processId)) {

        pair.setLeftObject(new ArrayList<BpmTransitionLine>());
        return pair;
      }

      /*
       * TaskQuery tq= taskService.createTaskQuery()
       * .processInstanceId(processId) .processDefinitionKey(processKey); String
       * t=tq.singleResult().getTaskDefinitionKey();
       * 
       * TaskQuery tq1=taskService.createTaskQuery()
       * .processInstanceId(processId);
       */

      List<Task> ts = taskService.createTaskQuery()
          .processInstanceId(processId).processDefinitionKey(processKey)
          .taskCandidateOrAssigned(username).list();

      if (ts == null || ts.size() == 0) {
        pair.setLeftObject(new ArrayList<BpmTransitionLine>());
        return pair;

      }

      String actId = ts.get(0).getTaskDefinitionKey();
      // 寻找流程定义的下一步
      // String actId = t.getTaskDefinitionKey();
      List<ActivityImpl> activitiList = def.getActivities();

      FIND_ACTIVITY: for (ActivityImpl activityImpl : activitiList) {
        String id = activityImpl.getId();
        if (actId.equals(id)) {
          thisActivity = activityImpl;
          ins = activityImpl.getOutgoingTransitions();
          break FIND_ACTIVITY;
        }
      }
    }

    List<BpmTransitionLine> lines = new ArrayList<BpmTransitionLine>();
    // 转换为连接线
    for (PvmTransition tran : ins) {
      if (tran == null) {
        break;
      }
      Object name = tran.getProperty("name");
      if (name == null) {
        continue;
      }
      // pvm的目标环节
      PvmActivity dest = getNextActivity(tran);
      BpmTransitionLine m = new BpmTransitionLine();
      m.setName(name.toString());
      m.setNextTransitionId(tran.getId());
      m.setNextTaskId(dest.getId());

      Map<String, Object> setting = bpmNodeSettingService.findMapByNodeId(
          m.getNextTaskId(), "commit_type", "are_open_comment_window",
          "are_auto_entry_next");
      m.setProcessInstanceId(processId);
      if (setting != null) {
        // null next will by a gateway
        Object commit_type = setting.get("commit_type");

        Boolean are_open_comment_window = false, are_auto_entry_next = false;

        if (setting.get("are_open_comment_window") instanceof Boolean) {
          are_open_comment_window = (Boolean) setting
              .get("are_open_comment_window");
        } else {
          are_open_comment_window = setting.get("are_open_comment_window") == null ? false
              : (Integer.valueOf(setting.get("are_open_comment_window")
                  .toString()) == 1 ? true : false);
        }
        if (setting.get("are_auto_entry_next") instanceof Boolean) {
          are_auto_entry_next = (Boolean) setting.get("are_auto_entry_next");
        } else {
          are_auto_entry_next = setting.get("are_auto_entry_next") == null ? false
              : (Integer.valueOf(setting.get("are_auto_entry_next").toString()) == 1 ? true
                  : false);
        }

        m.setCommitType(commit_type == null ? 0 : Integer.parseInt(commit_type
            .toString()));
        m.setAreOpenCommentWindow(are_open_comment_window);
        m.setAreAutoEntryNext(are_auto_entry_next);

      }
      lines.add(m);
    }
    Map<String, Object> nodeSetting = null;
    if (thisActivity != null) {
      // 获取节点设置上的按钮权限
      nodeSetting = bpmNodeSettingService.findMapByNodeId(thisActivity.getId(),
          "can_rollback", "mobile_handle_type");

      if (MapUtils.isNotEmpty(nodeSetting)) {

        Boolean can_rollback = false;
        if (nodeSetting.get("can_rollback") instanceof Boolean) {
          can_rollback = (Boolean) nodeSetting.get("can_rollback");
        } else {
          can_rollback = Integer.valueOf(nodeSetting.get("can_rollback")
              .toString()) == 1 ? true : false;
        }

        if (can_rollback) {
          BpmTransitionLine m = new BpmTransitionLine();
          m.setName("退回");
          m.setNextTransitionId(null);
          m.setNextTaskId(thisActivity.getId());
          m.setProcessMode(2);
          m.setProcessInstanceId(processId);
          lines.add(m);
        }

      }

    }

    pair.setLeftObject(lines);
    pair.setRightObject(nodeSetting);
    return pair;
  }

  /**
   * 获取下一个任务节点
   * 
   * @param tran
   *          连接线
   * @return 目标的任务节点
   */
  private PvmActivity getNextActivity(PvmTransition tran) {
    PvmActivity dest = tran.getDestination();

    String type = (String) dest.getProperty("type");
    switch (type) {
    case "userTask":
    case "exclusiveGateway":
      return dest;
    case "scriptTask":
    case "serviceTask":
      return getNextActivity(dest.getOutgoingTransitions().get(0));
    }
    return dest;

  }

  /**
   * 完成流程的环节任务（已废弃）
   * 
   * @param exeUsername
   *          执行者
   * @param businessKey
   *          业务key
   * @param comment
   *          审批意见
   * @param nextTranId
   *          下一步流程id
   * @param processMode
   *          流程运行提交方式（1，撤销；2，退回）
   * @throws SQLException
   */
  @Deprecated
  protected void complateProcessTask(String exeUsername, String businessKey,
      String comment, String nextTransitionId, int processMode)
      throws SQLException {

    // 获取到任务的
    Map<String, Object> variables = new HashMap<>();

    variables.put("bpmCurrentUser", exeUsername);
    variables.put("nextStepAssignee", null);
    Task t = this.taskService.createTaskQuery()
        .processInstanceBusinessKey(businessKey).active().singleResult();

    if (t == null) {
      throw new NullPointerException("无法取得任务");
    }

    String taskId = t.getId();
    String nodeId = t.getTaskDefinitionKey();

    taskService.claim(taskId, exeUsername);
    taskService.setAssignee(taskId, exeUsername);

    ActivityImpl currentActivityImpl = this.bpmProcessDefinitaionService
        .getActivityImpl(t.getProcessDefinitionId(), nodeId);

    if (StringUtils.isEmpty(nextTransitionId)) {
      Object default_tran = bpmNodeSettingService.findMapByNodeId(nodeId,
          "default_tran").get("default_tran");

      nextTransitionId = default_tran == null ? null : default_tran.toString();
    }

    List<PvmTransition> pvmTransitionList = currentActivityImpl
        .getOutgoingTransitions();

    if (pvmTransitionList.size() > 1) {
      List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();

      // List<Pair<TransitionImpl, ActivityImpl>> olds = new
      // ArrayList<Pair<TransitionImpl, ActivityImpl>>();
      PvmTransition destTran = null;
      if (StringUtils.isEmpty(nextTransitionId)) {
        destTran = pvmTransitionList.get(0);
        nextTransitionId = destTran.getId();
      }
      for (PvmTransition pvmTransition : pvmTransitionList) {

        if (nextTransitionId.equals(pvmTransition.getId())) {
          destTran = pvmTransition;

        }
        oriPvmTransitionList.add(pvmTransition);
      }

      pvmTransitionList.clear();
      pvmTransitionList.add(destTran);

      taskService.complete(taskId, variables);
      bpmActionHistoryService.save(t.getProcessInstanceId(), businessKey,
          taskId, destTran.getId(), (String) destTran.getProperty("name"),
          exeUsername, comment);
      pvmTransitionList.clear();
      for (PvmTransition pvmTransition : oriPvmTransitionList) {
        pvmTransitionList.add(pvmTransition);
      }
    } else {
      PvmTransition pv = pvmTransitionList.get(0);
      taskService.complete(taskId, variables);
      bpmActionHistoryService.save(t.getProcessInstanceId(), businessKey,
          taskId, pv.getId(), (String) pv.getProperty("name"), exeUsername,
          comment);

    }

  }

  public Pair<String, List<Map<String, Object>>> startProcess(final String key,
      final String businessKey, final String suggestion) throws SQLException {

    return startProcess(ContextHolder.getLoginUsername(), key, businessKey,
        suggestion);

  }

  /**
   * 启动新流程
   * 
   * @param key
   *          流程key
   * @param businessKey
   *          业务key
   * @param username
   *          用户帐号
   * @param suggestion
   *          意见
   * @return 下一步处理人列表
   * @throws SQLException
   */
  public Pair<String, List<Map<String, Object>>> startProcess(
      final String exeUsername, final String key, final String businessKey,
      final String suggestion) throws SQLException {

    return gotoNextSetp(exeUsername, key, null, null, null, businessKey, null,
        suggestion);

  }

  public Pair<String, List<Map<String, Object>>> gotoNextSetp(
      final String exeUsername, final String key, final String nextTaskId,
      final String nextTransitionId, final String processInstanceId,
      final String businessKey, final String nextAssigner,
      final String suggestion) throws SQLException {
    return gotoNextSetp(exeUsername, key, nextTaskId, nextTransitionId,
        processInstanceId, businessKey, nextAssigner, suggestion, 0, 0);
  }

  public Pair<String, List<Map<String, Object>>> gotoNextSetp(
      final String exeUsername, String key, String nextTaskId,
      String nextTransitionId, String processInstanceId, String businessKey,
      String nextAssigner, String suggestion, final int processMode)
      throws SQLException {
    return gotoNextSetp(exeUsername, key, nextTaskId, nextTransitionId,
        processInstanceId, businessKey, nextAssigner, suggestion, processMode,
        0);
  }

  public Pair<String, List<Map<String, Object>>> gotoNextSetp(final String key,
      String nextTaskId, String nextTransitionId, String processInstanceId,
      String businessKey, String nextAssigner, String suggestion)
      throws SQLException {
    return gotoNextSetp(key, nextTaskId, nextTransitionId, processInstanceId,
        businessKey, nextAssigner, suggestion, 0, 0);
  }

  public Pair<String, List<Map<String, Object>>> gotoNextSetp(String key,
      String nextTaskId, String nextTransitionId, String processInstanceId,
      String businessKey, String nextAssigner, String suggestion,
      final int processMode, final int commitType) throws SQLException {
    return gotoNextSetp(ContextHolder.getLoginUsername(), key, nextTaskId,
        nextTransitionId, processInstanceId, businessKey, nextAssigner,
        suggestion, processMode, commitType);
  }

  /**
   * 进入流程下一步
   * 
   * @param key
   *          流程定义key
   * @param nextTaskId
   *          下一步的任务id
   * @param processInstanceId
   *          流程定义id
   * @param businessKey
   *          业务数据的主键
   * @param name
   *          流程连接线名称
   * @param var
   *          流程提交变量
   * @return 流程下一步处理人列表
   * @throws Exception
   */
  public Pair<String, List<Map<String, Object>>> gotoNextSetp(
      final String exeUserName, String key, String nextNodeId,
      String nextTransitionId, String processInstanceId, String businessKey,
      final String nextAssigner, String suggestion, int processMode,
      final int commitType) throws SQLException {
    // StopWatch sw = new StopWatch();
    // StopWatch sw2 = new StopWatch();
    // sw2.start();
    // StringBuilder sb = new StringBuilder();

    if (StringUtils.isEmpty(businessKey)) {
      return null;
    }
    Pair<String, List<Map<String, Object>>> pair = new Pair<>();
    identityService.setAuthenticatedUserId(exeUserName);

    // --------
    // sw.start();
    DbEntity entity = bpmProcessSettingService.findDbEntityByKey(key);

    // sw.stop();
    // sb.append("findDbEntityByKey:").append(sw.getNanoTime()).append(";");
    // sw.reset();

    // --------
    // sw.start();
    // 加入一些常用变量以及实体变量包括:创建者,实体定义列的数据,以及动态dao对象(节点完成后销毁)
    Map<String, Object> entityMap = dbEntityService.getDataFromDbEntity(entity,
        businessKey);

    // sw.stop();
    // sb.append("getDataFromDbEntity:").append(sw.getNanoTime()).append(";");
    // sw.reset();
    String processDefinitionId = null;
    if (StringUtils.isEmpty(processInstanceId)
        || "null".equals(processInstanceId)) {

      String pid = (String) entityMap.get("process_id");

      if (StringUtils.isNotEmpty(pid)) {
        pair.setLeftObject("当前流程任务已存在，不能重复发起！");
        return pair;
      }

      // 获取一系列流程的值
      // 为了避免问题，大数据类型不应该交给流程中处理
      // 通过流程的key获取关联的业务实体的数据

      Map<String, Object> v = new HashMap<String, Object>();
      v.put("bpmStarter", exeUserName);

      v.put("nextStepAssignee", nextAssigner);
      v.put("bpmCurrentUser", exeUserName);
      v.put("businessKey", businessKey);
      v.put("bpmBusinessModel", entityMap);

      UserAccountService userAccountService = ContextHolder
          .getSpringBean("userAccountService");
      IUser u = userAccountService.findByUsername(exeUserName);

      v.put("bpmCurrentUserBean", u);
      ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
          .processDefinitionKey(key).latestVersion().singleResult();

      /* 下一步处理人 */
      if (commitType == 2) {

        int d = StringUtils.isEmpty(nextAssigner) ? 0
            : nextAssigner.split(",").length;
        v.put("signAllCount", d);
      }
      v.put("nextStepAssignee", nextAssigner);
      ProcessInstance pi = runtimeService.startProcessInstanceById(pd.getId(),
          businessKey, v);

      processDefinitionId = pi.getProcessDefinitionId();
      // 此处只是清空，并没有移除数据
      // runtimeService.removeVariable(pi.getId(), "bpmBusinessModel");
      // runtimeService.removeVariable(pi.getId(), "nextStepAssignee");
      // runtimeService.removeVariable(pi.getId(), "bpmCurrentUser");
      // runtimeService.removeVariable(pi.getId(), "bpmCurrentUserBean");

      bpmProcessSettingService.updateEntityTaskId(entity, businessKey,
          pi.getId());
      processInstanceId = pi.getId();

      List<Task> list = taskService.createTaskQuery()
          .processInstanceId(pi.getId()).active().list();
      // 发起
      bpmActionHistoryService.save(processInstanceId, businessKey, null, null,
          "提交", exeUserName, suggestion);

      if (list == null || list.size() == 0) {
        return null;
      }

      String sql = BpmConst.getQueryUsersByTask(processInstanceId, list);
      pair.setLeftObject("任务提交至");
      pair.setRightObject(jdbcTemplate.queryForList(sql));
      return pair;
    }
    // --------
    // sw.start();
    String taskId = getNextTaskId(exeUserName, processInstanceId, nextNodeId);
    // sw.stop();
    // sb.append("getNextTaskId:").append(sw.getNanoTime()).append(";");
    // sw.reset();

    if (StringUtils.isEmpty(taskId)) {
      List<Task> ts = this.taskService.createTaskQuery()
          .processInstanceId(processInstanceId).active().list();
      if (ts == null || ts.size() == 0) {
        pair.setLeftObject("当前流程任务不存在，无法提交！");
        return pair;
      }
      taskId = ts.get(0).getId();
    }

    if (processMode == 1) {
      int result = processEngine.getManagementService().executeCommand(
          new WithdrawTaskCmd(taskId, processInstanceId, exeUserName));
      // List<Map<String, Object>> l = new ArrayList<>();
      // 0撤销成功 1-流程结束 2-下一结点已经通过
      // Map<String, Object> mm = new HashMap<>();

      switch (result) {
      case 0:
        pair.setLeftObject("撤销成功");
        break;
      case 1:
        pair.setLeftObject("流程结束");
        break;
      case 2:
        pair.setLeftObject("下一结点已经通过,不能撤销");
        break;

      }
      List<Task> list = taskService.createTaskQuery()
          .processInstanceId(processInstanceId).active().list();
      if (list == null || list.size() == 0) {
        return null;
      }
      String sql = BpmConst
          .getQueryAssigneeUsersByTask(processInstanceId, list);

      pair.setRightObject(jdbcTemplate.queryForList(sql));
      return pair;

    } else if (processMode == 2) {
      // 0-退回成功 1-流程结束 2-下一结点已经通过,不能退回
      int result = processEngine.getManagementService().executeCommand(
          new RollbackTaskCmd(taskId, processInstanceId, suggestion,
              exeUserName));

      // List<Map<String, Object>> l = new ArrayList<>();
      // 0-退回成功 1-流程结束 2-下一结点已经通过,不能退回
      // Map<String, Object> mm = new HashMap<>();

      switch (result) {
      case 0:
        pair.setLeftObject("退回成功");
        break;
      case 1:
        pair.setLeftObject("流程结束");
        break;
      case 2:
        pair.setLeftObject("下一结点已经通过,不能退回");
        break;

      }
      List<Task> list = taskService.createTaskQuery()
          .processInstanceId(processInstanceId).active().list();
      if (list == null || list.size() == 0) {
        return null;
      }
      String sql = BpmConst
          .getQueryAssigneeUsersByTask(processInstanceId, list);

      pair.setRightObject(jdbcTemplate.queryForList(sql));
      return pair;
    }

    Map<String, Object> variables = new HashMap<>();

    variables.put("bpmCurrentUser", exeUserName);
    variables.put("bpmBusinessModel", entityMap);

    UserAccountService userAccountService = ContextHolder
        .getSpringBean("userAccountService");
    IUser u = userAccountService.findByUsername(exeUserName);

    variables.put("bpmCurrentUserBean", u);

    /* 下一步处理人 */
    if (commitType == 2) {

      int d = StringUtils.isEmpty(nextAssigner) ? 0
          : nextAssigner.split(",").length;
      variables.put("signAllCount", d);
    }
    variables.put("nextStepAssignee", nextAssigner);
    // variables.put("bpmBusinessModel", entityMap);
    // 当前人获取
    // sw2.stop();
    //
    // sb.append("all1:").append(sw2.getNanoTime());
    // sw2.reset();
    // --------
    // sw.start();

    taskService.claim(taskId, exeUserName);
    // sw.stop();
    // sb.append("claim:").append(sw.getNanoTime()).append(";");
    // sw.reset();
    taskService.setAssignee(taskId, exeUserName);

    TaskEntity t = (TaskEntity) taskService.createTaskQuery().taskId(taskId)
        .singleResult();

    processDefinitionId = t.getProcessDefinitionId();

    String tkey = t.getTaskDefinitionKey();
    // 下一步
    variables.put("outcome", nextTransitionId);

    // --------
    // sw.start();
    ProcessDefinitionEntity def = this.bpmProcessDefinitaionService
        .getProcessDefinitionEntityByProcessDefinitionId(processDefinitionId);

    ActivityImpl currentActivityImpl = def.findActivity(tkey);

    // sw.stop();
    // sb.append("getProcessDefinitionEntityByProcessDefinitionId:")
    // .append(sw.getNanoTime()).append(";");
    // sw.reset();

    List<PvmTransition> pvmTransitionList = currentActivityImpl
        .getOutgoingTransitions();
    // --------
    // sw.start();
    if (pvmTransitionList != null && pvmTransitionList.size() > 1) {

      PvmTransition destTran = null;

      FIND_DESTTRAN: for (PvmTransition pvmTransition : pvmTransitionList) {
        if (nextTransitionId.equals(pvmTransition.getId())) {
          destTran = pvmTransition;
          break FIND_DESTTRAN;
        }

      }

      bpmActionHistoryService.save(processInstanceId, businessKey, taskId,
          destTran.getId(), (String) destTran.getProperty("name"), exeUserName,
          suggestion);

      taskService.complete(taskId, variables);

    } else {

      PvmTransition destTran = pvmTransitionList.get(0);
      bpmActionHistoryService.save(processInstanceId, businessKey, taskId,
          destTran.getId(), (String) destTran.getProperty("name"), exeUserName,
          suggestion);
      taskService.complete(taskId, variables);
    }
    // sw.stop();
    // sb.append("complete:").append(sw.getNanoTime()).append(";");
    // sw.reset();
    // // --------
    // sw.start();
    List<Task> list = taskService.createTaskQuery()
        .processInstanceId(processInstanceId).active().list();

    // sw.stop();
    // sb.append("createTaskQuery:").append(sw.getNanoTime()).append(";");
    // sw.reset();
    if (list == null || list.size() == 0) {
      return null;
    }
    pair.setLeftObject("任务提交至");// --------
    // sw.start();
    pair.setRightObject(jdbcTemplate.queryForList(BpmConst.getQueryUsersByTask(
        processInstanceId, list)));
    // sw.stop();
    // sb.append("getQueryUsersByTask:").append(sw.getNanoTime()).append(";");
    // sw.reset();
    // sw2.stop();
    // sb.append("all:").append(sw2.getNanoTime());
    return pair;
  }

  /**
   * 删除流程
   * 
   * @param processInstanceIdF
   * @param exeUsername
   */
  public void deleteProcessInstance(String processInstanceId, String exeUsername) {
    this.deleteProcessInstance(processInstanceId, "delete", exeUsername);
  }

  /**
   * 删除流程
   * 
   * @param processInstanceId
   * @param deleteReason
   * @param exeUsername
   */
  public void deleteProcessInstance(String processInstanceId,
      String deleteReason, String exeUsername) {

    ProcessInstance pi = runtimeService.createProcessInstanceQuery()
        .processInstanceId(processInstanceId).singleResult();
    String processDefinitionId =

    pi.getProcessDefinitionId();

    BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

    org.activiti.bpmn.model.Process p = bpmnModel.getProcesses().get(0);
    String activityId = null;
    Collection<FlowElement> elements = p.getFlowElements();
    FOREACH_ELEMENTS: for (FlowElement fe : elements) {
      if (fe instanceof EndEvent) {
        activityId = fe.getId();

        break FOREACH_ELEMENTS;
      }
    }

    if (activityId == null) {
      runtimeService.deleteProcessInstance(processInstanceId, "delete");

      bpmActionHistoryService.save(processInstanceId, pi.getBusinessKey(),
          null, null, "", exeUsername, "结束流程");

    } else {
      processEngine.getManagementService().executeCommand(
          new JumpCmd(processInstanceId, activityId, exeUsername, "delete"));

    }

  }

  public Object jumpto(String processInstanceId, String activityId,
      String exeUsername, String suggestion) {
    return processEngine.getManagementService().executeCommand(
        new JumpCmd(processInstanceId, activityId, exeUsername, "干预",
            suggestion));

  }

  /**
   * 终止流程
   * 
   * @param exeUserName
   * @param processKey
   * @param processInstanceId
   * @param suggestion
   * @throws Exception
   */
  public boolean endProcessByBusinessId(final String exeUserName,
      final String businessId, final String suggestion) throws Exception {
    String processId = this.runtimeService.createProcessInstanceQuery()
        .processInstanceBusinessKey(businessId).active().singleResult()
        .getProcessInstanceId();
    this.deleteProcessInstance(processId, exeUserName);
    return true;
  }

  /**
   * 终止流程
   * 
   * @param exeUserName
   * @param processKey
   * @param processInstanceId
   * @param suggestion
   * @throws Exception
   */
  public boolean endProcess(final String exeUserName,
      final String processInstanceId, final String suggestion) throws Exception {

    Map<String, Object> variables = new HashMap<>();

    variables.put("bpmCurrentUser", exeUserName);

    List<Task> ts = taskService.createTaskQuery()
        .processInstanceId(processInstanceId).list();

    ProcessDefinitionEntity def = this.bpmProcessDefinitaionService
        .getProcessDefinitionEntityByProcessInstanceId(processInstanceId);
    List<ActivityImpl> activitiList = def.getActivities();
    ProcessInstance pi = this.runtimeService.createProcessInstanceQuery()
        .processInstanceId(processInstanceId).singleResult();

    ActivityImpl currentActivityImpl = null;
    boolean b = false;
    for (Task t : ts) {
      String tkey = t.getTaskDefinitionKey();
      FIND_CURRENT_ACTIVITY: for (ActivityImpl activityImpl : activitiList) {
        String id = activityImpl.getId();
        if (id.equals(tkey)) {
          currentActivityImpl = activityImpl;
          break FIND_CURRENT_ACTIVITY;
        }
      }

      EXEACTIVITY: for (ActivityImpl activityImpl : activitiList) {
        List<PvmTransition> pvmTransitions = activityImpl
            .getOutgoingTransitions();

        if (pvmTransitions != null && pvmTransitions.isEmpty()) {

          try {
            // 为了避免流程中提交时因为情况连接线而导致流程错误而加入锁的概念
            lockEnd.lock();

            b = this.turnTransition(currentActivityImpl, activityImpl,
                exeUserName, t.getId(), variables);
            bpmActionHistoryService.save(processInstanceId,
                pi.getBusinessKey(), t.getId(), null, "终止", exeUserName,
                suggestion);

          } finally {
            lockEnd.unlock();
          }

          break EXEACTIVITY;
        }

      }
    }

    return b;
  }

  /**
   * 清空指定活动节点流向
   * 
   * @param activityImpl
   *          活动节点
   * @return 节点流向集合
   */
  private List<PvmTransition> clearTransition(ActivityImpl activityImpl) {
    // 存储当前节点所有流向临时变量
    List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
    // 获取当前节点所有流向，存储到临时变量，然后清空
    List<PvmTransition> pvmTransitionList = activityImpl
        .getOutgoingTransitions();
    for (PvmTransition pvmTransition : pvmTransitionList) {
      oriPvmTransitionList.add(pvmTransition);
    }
    pvmTransitionList.clear();

    return oriPvmTransitionList;
  }

  /**
   * 还原指定活动节点流向
   * 
   * @param activityImpl
   *          活动节点
   * @param oriPvmTransitionList
   *          原有节点流向集合
   */
  private void restoreTransition(ActivityImpl activityImpl,
      List<PvmTransition> oriPvmTransitionList) {
    // 清空现有流向
    List<PvmTransition> pvmTransitionList = activityImpl
        .getOutgoingTransitions();
    pvmTransitionList.clear();
    // 还原以前流向
    for (PvmTransition pvmTransition : oriPvmTransitionList) {
      pvmTransitionList.add(pvmTransition);
    }
  }

  /**
   * 进入流程
   * 
   * @param currActivity
   * @param pointActivity
   * @param exeUserName
   * @param taskId
   * @param variables
   * @throws Exception
   */
  private boolean turnTransition(ActivityImpl currActivity,
      ActivityImpl pointActivity, String exeUserName, String taskId,
      Map<String, Object> variables) throws Exception {

    // 清空当前流向
    List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity);

    // 创建新流向
    TransitionImpl newTransition = currActivity.createOutgoingTransition();
    // 目标节点
    // 设置新流向的目标节点
    newTransition.setDestination(pointActivity);
    try {
      // 当前人获取
      taskService.claim(taskId, exeUserName);
      taskService.setAssignee(taskId, exeUserName);
      // 执行转向任务
      taskService.complete(taskId, variables);
    } catch (Exception e) {
      logger.error("end process error：", e);
      return false;

    }
    // 删除目标节点新流入
    pointActivity.getIncomingTransitions().remove(newTransition);

    // 还原以前流向
    restoreTransition(currActivity, oriPvmTransitionList);
    return true;
  }

  /**
   * 获取下一步可用的处理人（未分配时）
   * 
   * @param key
   *          流程端口
   * @param processInstanceId
   * @param nextNodeId
   * @return
   */
  public Collection<IUser> getNextSetpUser(String key,
      String processInstanceId, String nextNodeId, String businessKey,
      String exeUsername, int processMode) {
    // rollback
    if (processMode == 2) {

      String taskId = getNextTaskId(ContextHolder.getLoginUsername(),
          processInstanceId, nextNodeId);

      logger.debug("rollback current task:{}", taskId);

      String historyTaskId = processEngine.getManagementService()
          .executeCommand(new FindNearestUserTaskCmd(taskId));
      logger.debug("rollback current historic task:{}", taskId);

      String username = null;

      if (historyTaskId == null) {
        HistoricProcessInstance hpi = this.historyService
            .createHistoricProcessInstanceQuery()
            .processInstanceId(processInstanceId).singleResult();
        username = hpi.getStartUserId();
      } else {
        HistoricTaskInstance ht = this.historyService
            .createHistoricTaskInstanceQuery().taskId(historyTaskId)
            .singleResult();
        username = ht.getAssignee();
      }
      List<IUser> mapUsers = new ArrayList<>();

      UserAccountService userAccountService = ContextHolder
          .getSpringBean("userAccountService");

      IUser u = userAccountService.findByUsername(username);
      mapUsers.add(u);

      return mapUsers;

    } else {
      BpmNodeUserService bs = ContextHolder.getSpringBean("bpmNodeUserService");

      List<BpmNodeUser> users = bs.findAllCandidaterByDefKeyAndNodeId(key,
          nextNodeId);

      Map<String, IUser> mapUsers = new HashMap<>();
      // String nextTaskId = getNextTaskId(processInstanceId, nextNodeId);

      for (BpmNodeUser user : users)
        CandidaterUtils.addToCandidater(bs, mapUsers, processInstanceId, user,
            key, businessKey);

      return mapUsers.values();
    }

  }

  /**
   * 获取下一步待处理人
   * 
   * @param businessKey
   *          key
   * @return
   */
  public List<Map<String, Object>> getNextSetpAssignee(String businessKey) {
    String sql = BpmConst.getQueryUsersByBusinessKey(businessKey);

    return jdbcTemplate.queryForList(sql);
  }

  /**
   * 获取流程的下一个节点任务的id，用于获取当前用户是否具有节点权限等
   * 
   * @param processInstanceId
   *          流程实例id
   * @param nextNodeId
   *          请求进入的节点id
   * @return
   */
  private String getNextTaskId(String username, String processInstanceId,
      String nextNodeId) {
    String sql = BpmConst.getQueryMyTaskId(processInstanceId, username);
    try {
      return jdbcTemplate.queryForObject(sql, String.class);
    } catch (Exception ex) {
      return null;
    }

  }

  /**
   * 转办流程
   * 
   * @param processInstanceId
   *          流程实例id
   * @param username
   *          被转办人帐号
   */
  public void transferAssignee(String processInstanceId, String exeUsername,
      String assignee, String suggestion) {

    List<Task> taskList = taskService.createTaskQuery()
        .processInstanceId(processInstanceId).list();

    String businessKey = this.runtimeService.createProcessInstanceQuery()
        .processInstanceId(processInstanceId).singleResult().getBusinessKey();

    for (Task t : taskList) {

      bpmActionHistoryService.save(processInstanceId, businessKey, t.getId(),
          t.getTaskDefinitionKey(), "转派", exeUsername, suggestion);

      List<IdentityLink> ls = taskService.getIdentityLinksForTask(t.getId());

      taskService.unclaim(t.getId());
      for (IdentityLink ident : ls) {
        taskService.deleteCandidateUser(t.getId(), ident.getUserId());
      }
      taskService.setAssignee(t.getId(), assignee);

      try {
        BpmScriptUtils.transferAssigneeScript(assignee, processInstanceId,
            t.getId(), t.getTaskDefinitionKey(), businessKey);
      } catch (Exception e) {
        logger.error(e.getMessage(), e);
      }

    }

  }

  /**
   * 会签<strong>操作</strong>
   * 
   * @param taskId
   *          当前任务ID
   * @param userCodes
   *          会签人账号集合
   * @throws Exception
   */
  public void jointProcess(String processInstanceId, String taskId,
      List<String> userCodes) throws Exception {
    for (String userCode : userCodes) {
      TaskEntity task = (TaskEntity) taskService.newTask(HibernateUUIDGenerator
          .generate());
      task.setAssignee(userCode);
      task.setName(findTaskById(taskId).getName() + "-会签");
      task.setProcessDefinitionId("?");
      task.setProcessInstanceId(processInstanceId);
      task.setParentTaskId(taskId);
      task.setDescription("jointProcess");
      taskService.saveTask(task);
    }
  }

  /**
   * 取得任务实体类
   * 
   * @param taskId
   * @return
   * @throws Exception
   */
  private TaskEntity findTaskById(String taskId) throws Exception {
    TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(taskId)
        .singleResult();
    if (task == null) {
      throw new Exception("任务实例未找到!");
    }
    return task;
  }

  /**
   * 
   * @param processInstanceId
   * @return
   */
  public HistoricProcessInstance getProcessFinished(String processInstanceId) {
    return historyService.createHistoricProcessInstanceQuery()
        .processInstanceId(processInstanceId).finished().singleResult();
  }

  public ProcessInstance getProcessInstanceByBusinessKey(String businessKey) {
    return this.runtimeService.createProcessInstanceQuery()
        .processInstanceBusinessKey(businessKey).singleResult();
  }

  /**
   * 
   * @param processInstanceId
   * @return
   */
  public boolean isProcessFinished(String processInstanceId) {
    return getProcessFinished(processInstanceId) != null;

  }

  /**
   * 获取已完成的流程实例
   * 
   * @param businessKey
   * @param processDefinitionKey
   * @return
   */
  @Deprecated
  public HistoricProcessInstance getProcessFinishedByBusinessKey(
      String businessKey) {
    return historyService.createHistoricProcessInstanceQuery()
        .processInstanceBusinessKey(businessKey).finished().singleResult();

  }

  /**
   * 判断流程是否结束
   * 
   * @param processDefinitionKey
   * @param processInstanceId
   * @return
   */
  @Deprecated
  public boolean isProcessInstanceFinished(String processDefinitionKey,
      String processInstanceId) {
    return historyService.createHistoricProcessInstanceQuery()
        .processInstanceId(processInstanceId)
        .processDefinitionKey(processDefinitionKey).finished().singleResult() != null;

  }

  /**
   * 获取流程跟踪信息
   * 
   * @param processId
   * @return
   */
  public Map<String, Object> trace(String processId) {
    Map<String, Object> map = new HashMap<>();
    List<Map<String, Object>> historys = this.getHistory(processId);

    map.put("historys", historys);

    TaskService taskService = ContextHolder.getSpringBean("taskService");

    List<Task> taskList = taskService.createTaskQuery()
        .processInstanceId(processId).orderByTaskCreateTime().desc().list();
    if (taskList != null) {

      for (Task t : taskList) {
        map.put("areRunning", "1");

        String sql = BpmConst.getQueryUsersByTask(processId, t.getId());
        JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");

        map.put("currentTaskName", t.getName());

        map.put("currentTaskTaskDefinitionKey", t.getTaskDefinitionKey());
        map.put("currentTaskCreateTime", new Timestamp(t.getCreateTime()
            .getTime()));
        try {

          List<Map<String, Object>> listUser = jdbcTemplate.queryForList(sql);
          String uStr = (String) listUser.get(0).get("fullname");
          for (int i = 1; i < listUser.size(); i++) {
            uStr += "," + (String) listUser.get(i).get("fullname");
          }
          map.put("currentUserList", listUser);
          map.put("currentUsers", uStr);
        } catch (Exception ex) {
          map.put("currentUsers", "");
        }
      }

    }

    return map;

  }

  /**
   * 待办任务列表
   */
  public List<Map<String, Object>> getAllTodoList(String username,
      DataRequest req) {
    StringBuilder sb = BpmConst.getProcessListSql(req);
    String myProcess = BpmConst.getQueryMyAllTaskSqlCondition(username);
    sb.append(" AND " + myProcess);
    // 如果req中有排序字段，则将排序字段加在最后面
    if (req != null && req.getOrderSql() != null && req.getOrderSql() != "") {
      sb.append(req.getOrderSql());
    }
    return jdbcTemplate.queryForList(sb.toString());
  }

  /**
   * 已办任务列表
   */
  public DataResponse<Map<String, Object>> getAllTodoneList(String username,
      JqGridRequest req) {
    StringBuilder sb = BpmConst.getProcessListSql(req);
    String myProcess = BpmConst
        .getQueryMyTaskAttendOfAllProcessSqlCondition(username);
    sb.append(" AND " + myProcess);

    long total = jdbcTemplate.queryForObject(
        "SELECT COUNT(*) AS count_t FROM (" + sb.toString() + ") table_t",
        Long.class);

    // 如果req中有排序字段，则将排序字段加在最后面
    if (req != null && req.getOrderSql() != null && req.getOrderSql() != "") {
      sb.append(req.getOrderSql());
    }
    String pageSqlStr = sb.toString();
    pageSqlStr = DialectFactory.getDialect().getLimitString(pageSqlStr,
        req.getOffset(), req.getRows());

    List<Map<String, Object>> list = jdbcTemplate.queryForList(pageSqlStr);

    DataResponse<Map<String, Object>> res = new JqGridResponseData<Map<String, Object>>(
        list, req, total);

    return res;
  }

  /**
   * 获取个人待办任务总数
   * 
   * @param username
   * @param req
   * @return
   */
  public Integer getAllTodoCount(String username, DataRequest req) {
    StringBuilder sb = BpmConst.getProcessListSql(req);
    String myProcess = BpmConst.getQueryMyAllTaskSqlCondition(username);
    sb.append(" AND " + myProcess);
    return jdbcTemplate.queryForObject("SELECT COUNT(1) FROM (" + sb.toString()
        + ") table_t", Integer.class);
  }

  /**
   * 获取个人已办数
   * 
   * @param username
   * @param req
   * @return
   */
  public Integer getAllTodoneCount(String username, DataRequest req) {
    StringBuilder sb = BpmConst.getProcessListSql(req);
    String myProcess = BpmConst
        .getQueryMyTaskAttendOfAllProcessSqlCondition(username);
    sb.append(" AND " + myProcess);
    return jdbcTemplate.queryForObject("SELECT COUNT(1) FROM (" + sb.toString()
        + ") table_t", Integer.class);
  }

  public DataResponse<Map<String, Object>> findProcess(JqGridRequest req) {
    ActHiProcinstService actHiProcinstService = ContextHolder
        .getSpringBean("actHiProcinstService");

    return actHiProcinstService.findAllDetailByRequest(req);
  }

  public List<Node> getUserTaskByProcessInstanceId(String processInstanceId) {

    ProcessDefinitionImpl pd = this.bpmProcessDefinitaionService
        .getProcessDefinitionEntityByProcessInstanceId(processInstanceId)
        .getProcessDefinition();

    List<ActivityImpl> activities = pd.getActivities();
    List<Node> nodes = new ArrayList<>();
    for (ActivityImpl act : activities) {
      Map<String, Object> m = act.getProperties();
      if ("userTask".equals(m.get("type").toString())) {
        Node n = new Node();
        n.setId(act.getId());
        n.setName(m.get("name").toString());
        nodes.add(n);
      }

    }

    return nodes;

  }

}
